package com.mpsc.current.common;

import com.mpsc.current.annotation.CacheLock;
import com.mpsc.current.annotation.CacheParam;
import io.lettuce.core.dynamic.support.ReflectionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;

@Component
public class LockKeyGenerator implements CacheKeyGenerator {

    @Override
    public List<String> getLockKey(ProceedingJoinPoint pjp) {
        List<String> LockKeyList = new ArrayList<>();
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        CacheLock lockAnnotation = method.getAnnotation(CacheLock.class);
        final Object[] args = pjp.getArgs();
        final Parameter[] parameters = method.getParameters();
        //LockKeyPrefix分布式锁前缀
        String LockKeyPrefix = lockAnnotation.prefix() + lockAnnotation.delimiter();
        StringBuilder builder = null;
        //默认解析方法里面带 CacheParam 注解的属性,如果没有尝试着解析实体对象中的
        for (int i = 0; i < parameters.length; i++) {
            final CacheParam annotation = parameters[i].getAnnotation(CacheParam.class);
            if (annotation == null)
                continue;
            String separator = annotation.separator();
            String[] fieldValues = ((String) args[i]).split(separator);
            if (fieldValues.length > 0) {
                for (int fiel = 0, len = fieldValues.length; fiel < len; fiel++) {
                    builder = new StringBuilder(LockKeyPrefix).append(fieldValues[i]);
                    LockKeyList.add(builder.toString());
                }
            }
        }
        if (CollectionUtils.isEmpty(LockKeyList)) {
            final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            for (int i = 0; i < parameterAnnotations.length; i++) {
                final Object object = args[i];
                final Field[] fields = object.getClass().getDeclaredFields();
                for (Field field : fields) {
                    final CacheParam annotation = field.getAnnotation(CacheParam.class);
                    if (annotation == null)
                        continue;
                    field.setAccessible(true);
                    Object fieldObject = ReflectionUtils.getField(field, object);
                    String separator = annotation.separator();
                    String[] fieldValues = ((String) fieldObject).split(separator);
                    if (null != fieldValues && fieldValues.length > 0) {
                        for (int fiel = 0, len = fieldValues.length; fiel < len; fiel++) {
                            builder = new StringBuilder(LockKeyPrefix).append(fieldValues[fiel]);
                            LockKeyList.add(builder.toString());
                        }
                    }
                }
            }
        }

        return LockKeyList;
    }

}
